package com.sl.mes.app.service.puboid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.System.in;

public class OidGenerator {
    private static String INTERN_FIXER = "AA";
    private Map<String, Lock> locks = new HashMap();
    private static final Logger logger = LoggerFactory.getLogger(OidGenerator.class);
    public static final String GROUP_PK_CORP = "0001";
    private Object lock;
    //    protected OidGeneratorBS oidGeneratorBS;
    private static Map<String, OidCounter> oidMap = new ConcurrentHashMap();
    private static OidGenerator instance = new OidGenerator();
    public static final int OID_AMOUNT = 1000;
    public static final String OID_BASE_INITIAL_VAL = "10000000000000";

    PubOidService oidGeneratorBS = new PubOidService();

    private OidGenerator() {
        try {
            this.lock = new Object();
        } catch (Exception e) {
            logger.error("Cannot initialize OidGenerator.");
        }
    }

    private class OidCounter {
        public String oidBase;

        public int amount;

        public OidCounter() {
            this.amount = 0;
            this.oidBase = "10000000000000";
        }
    }

    public static OidGenerator getInstance() {
        return instance;
    }

    public final String nextOid() {
        return nextOid("0001");
    }


    public final String[] nextOid(String groupNumber, int count) {
        String[] oids = new String[count];
        for (int i = 0; i < count; i++) {
            String oid = nextOid(groupNumber);
            oids[i] = oid;
        }
        return oids;
    }

    public final String[] nextOid(String dataSource, String groupNumber, int count) {
        String[] oids = new String[count];
        for (int i = 0; i < count; i++) {
            String oid = nextOid(dataSource, groupNumber);
            oids[i] = oid;
        }
        return oids;
    }

    public String nextOid(String dataSource, String groupNumber) {
        String ds = dataSource;

        if (dataSource == null) {
            ds = getDataSource();
        }

        OidCounter oidCounter = null;
        String oidBase = null;


        String oidMark = "AA";
        if ((oidMark == null) || (oidMark.length() != 2)) {
            oidMark = INTERN_FIXER;
        }

        Lock l = getLock(ds, groupNumber);

        l.lock();
        String nextOid;
        try {
            String key = groupNumber + ds;
            oidCounter = (OidCounter) oidMap.get(key);
            if (oidCounter == null) {
                oidCounter = new OidCounter();
                oidMap.put(key, oidCounter);
            }

            if ((oidCounter.amount % 1000 == 0) || (0 == oidCounter.amount)) {
                oidBase = this.oidGeneratorBS.selectForUpdateOidBase(groupNumber);
            } else {
                oidBase = oidCounter.oidBase;
            }

            nextOid = OidBaseAlgorithm.getInstance(oidBase).nextOidBase();
            oidCounter.oidBase = nextOid;
            oidCounter.amount += 1;
        } finally {
            l.unlock();
        }
        return getWholeOid(groupNumber, oidMark, nextOid);
    }


    public String nextOid(String groupNumber) {
        String ds = getDataSource();
        return nextOid(ds, groupNumber);
    }

    private String getDataSource() {
        return "design";
    }

    private final String getWholeOid(String groupNumber, String oidMark, String oidBase) {
        return groupNumber + oidMark + oidBase;
    }


    private Lock getLock(String ds, String groupNumber) {
        String lockKey = "" + ds + ":" + groupNumber;
        Lock l = null;
        synchronized (this.lock) {
            l = (Lock) this.locks.get(lockKey);
            if (l == null) {
                l = new ReentrantLock();
                this.locks.put(lockKey, l);
            }
        }
        return l;
    }
}
